import random

from flask import current_app
from flask import make_response
from flask import request, jsonify, session

from info.utils.response_code import RET
from info.models import User
from info.utils.captcha.captcha import captcha
#导入运通讯
from info.libs.yuntongxun import sms
#导入蓝图
from . import passport_blu
#导入redis实例
from info import redis_store, constants, db
#导入re模块，正则验证手机号
import re

#创建视图
@passport_blu.route('/image_code')
def generate():
    """
    生成图片验证码思路
    1、获取参数，根据前端发送的UUID生成图片验证码的后缀
    2、校验参数的完整性（即是否存在）
    3、调用扩展生成图片验证码
    4、将图片验证码内容保存到redis数据库中
    5、使用响应对象返回图片验证码本身给前端，修改默认的数据类型


    :return:
    """


    #获取参数
    image_code_id = request.args.get('image_code_id')
    #判断参数是否存在
    if not image_code_id:
        return jsonify(errno=RET.PARAMERR, errmsg='参数缺失')
    #调用扩展来生成图片验证码
    name,text,image = captcha.generate_captcha()

    #保存图片验证码到redis数据库
    try:
        redis_store.setex('ImageCode_' + image_code_id, constants.IMAGE_CODE_REDIS_EXPIRES, text)
    except Exception as e:
        # 记录操作数据库异常信息
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='保存图片验证码失败')
    else:
        #使用响应对象返回图片本身
        response = make_response(image)
        #设置响应的数据类型
        response.headers['Content-Type'] = 'image/jpg'
        #返回响应
        return response

@passport_blu.route('/sms_code', methods=['POST'])
def send_sms_code():
    """
    发送短信思路
    1、获取参数
    2、校验参数的完整性（即是否存在）
    3、校验手机号格式是否正确
    4、从redis数据库中读取图片验证码内容
    5、校验验证码是否已过期
    6、删除redis中的图片验证码，因为验证码只能验证一次
    7、比较验证码的一致性， 不区分大小写
    8、根据手机号查询mysql数据库，查看手机号是否已经注册过
    9、生成6位随机数保存到redis数据库中
    10、调用云通讯工具发送短信
    11、判断是否发送成功
    :return:
    """

    #获取前端用ajax发送过来的手机号，图片内容，图片编号
    mobile = request.json.get('mobile')

    image_code = request.json.get('image_code')
    image_code_id = request.json.get('image_code_id')
    print(mobile)
    print(image_code)
    print(image_code_id)
    #检查参数的完整性
    if not all([mobile, image_code, image_code_id]):
        return jsonify(errno=RET.PARAMERR, errmsg='参数不完整')
    #检查手机格式
    if not re.match(r'1[3456789]\d{9}', mobile):
        return jsonify(errno=RET.PARAMERR, errmsg='手机号格式不完整')
    #从redis数据库中读取图片验证码
    try:
        real_image_code = redis_store.get('ImageCode_' + image_code_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='获取图片验证码失败')
    #校验图片验证码是否过期
    if not real_image_code:
        return jsonify(errno=RET.NODATA, errmsg='验证码已过期')
    #删除图片验证码，因为每个验证码只能校验一次
    try:
        redis_store.delete('ImageCode_' + image_code_id)
    except Exception as e:
        current_app.logger.error(e)

    #对比图片验证码，不区分大小写
    if real_image_code.lower() != image_code.lower():
        return jsonify(errno=RET.DATAERR, errmsg='图片验证码不一致')
    #验证码一致后校验手机是否注册过
    try:
        user = User.query.filter_by(mobile=mobile).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='查询用户信息失败')
    else:
        #如果手机号不为空
        if user is not None:
            return jsonify(errno=RET.DATAEXIST, errmsg='手机号已注册')

    #构造6位随机数
    sms_code = '%06d' % random.randint(0, 999999)
    #保存到redis数据库中
    try:
        redis_store.setex('SMSCode_' + mobile, constants.SMS_CODE_REDIS_EXPIRES, sms_code)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DATAERR, errmsg='保存数据失败')
    #调用运通寻，发送手机验证码
    try:
        ccp = sms.CCP()

        result = ccp.send_template_sms(mobile, [sms_code, constants.SMS_CODE_REDIS_EXPIRES/6], 1)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.THIRDERR, errmsg='发送短信异常')
    #判断发送是否成功
    if result == 0:
        return jsonify(errno=RET.OK, errmsg='发送成功')
    else:
        return jsonify(errno=RET.THIRDERR, errmsg='发送失败')

@passport_blu.route('/register', methods=['POST'])
def register():
    """
    注册用户思路
    1、获取参数
    2、校验参数的完整性（即是否存在）
    3、检查手机号格式是否正确
    4、尝试从redis数据库中读取真实的短信验证码
    5、短信验证码进行比较
    6、如果验证码正确，删除redis数据库中的短信验证码
    7、从mysql数据库中读取手机号，判断手机号是否注册过
    8、构建模型类，准备储存用户信息
    9、对密码进行加密处理
    10、保存数据到mysql数据库中
    11、缓存用户信息到redis数据库中
    12、返回结果
    :return:
    """
    #1、获取参数
    mobile = request.json.get('mobile')
    sms_code = request.json.get('sms_code')
    password = request.json.get('password')
    #2、校验参数完整性
    if not all([mobile, sms_code, password]):
        return jsonify(errno=RET.PARAMERR, errmsg='参数不完整')
    #3、检查手机号格式是否正确
    if not re.match(r'^1[3456789]\d{9}$', mobile):
        return jsonify(errno=RET.PARAMERR, errmsg='手机号格式不正确')
    #4、尝试从redis数据库中读取真实的短信验证码
    try:
        real_sms_code = redis_store.get('SMSCode_' + mobile)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='获取数据失败')
    #5、判断获取短信验证码是否存在
    if not real_sms_code:
        return jsonify(errno=RET.NODATA, errmag='短信验证码已过期')
    #6、对比短信验证码
    if real_sms_code != sms_code:
        return jsonify(errno=RET.DATAERR, errmsg='验证码不正确')
    #7、删除redis数据库中的短信验证码
    try:
        redis_store.delete('SMSCode_' + mobile)
    except Exception as e:
        current_app.logger.error(e)
    #8、从mysql数据库中读取手机号
    try:
        user = User.query.filter_by(mobile=mobile).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='查询用户数据失败')
    #9、判断手机号是否存在
    if user:
        return jsonify(errno=RET.DATAERR, errmsg='手机号已注册')
    #10、构建模型类，准备存储用户信息
    user = User()
    user.mobile = mobile
    user.nick_name = mobile
    #对密码进行加密，调用User类中加密方法
    user.password = password
    #11、把数据提交到数据库中
    try:
        db.session.add(user)
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        #提交数据失败，需要回滚
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg='保存数据失败')
    #12、缓存用户信息到redis数据库中
    session['user_id'] = user.id
    session['mobile'] = mobile
    session['nick_name'] = mobile
    #13、返回结果
    return jsonify(errno=RET.OK, errmsg='注册成功')

@passport_blu.route('/login', methods=['POST'])
def login():
    """
    用户登录思想
    1、获取参数
    2、校验参数
    3、校验手机号格式是否正确
    4、尝试根据手机号从mysql数据库中读取手机号，获取用户信息
    5、对密码进行校验
    6、缓存数据到redis数据库中
    7、返回结果
    :return:
    """
    mobile = request.json.get('mobile')
    password = request.json.get('password')
    if not all([mobile, password]):
        return jsonify(errno=RET.PARAMERR, errmsg='参数缺省')
    if not re.match(r'^1[3456789]\d{9}$', mobile):
        return jsonify(errno=RET.PARAMERR, errmsg='手机号格式不正确')
    try:
        user = User.query.filter_by(mobile=mobile).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='查询数据失败')
    if user is None or not user.check_password(password):
    # if not all([user, user.check_password(password)]):

        return jsonify(errno=RET.DATAERR, errmsg='用户名或密码错误')
    session['user_id'] = user.id
    session['mobile'] = user.mobile
    session['nick_name'] = user.nick_name
    return jsonify(errno=RET.OK, errmsg='登录成功')


@passport_blu.route('/logout')
def logout():
    """
    用户退出
    本质是把缓存的数据清除
    :return:
    """
    session.pop('user_id')
    session.pop('mobile')
    session.pop('nick_name')
    return jsonify(errno=RET.OK, errmsg='退出')



